package org.kernely.scheduling.administration;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

import org.kernely.scheduling.KernelyQuartzScheduler;
import org.kernely.scheduling.SchedulingBundle;
import org.kernely.ui.mvp.KernelyEvent;
import org.kernely.ui.mvp.KernelyEventReceiver;
import org.kernely.ui.mvp.KernelyPresenter;
import org.kernely.ui.utils.KernelyDialogWindow;
import org.kernely.ui.utils.KernelyNotification;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
import org.quartz.Trigger;

import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.ui.Button;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

public class SchedulingAdminPresenter extends KernelyPresenter<SchedulingAdminView> implements KernelyEventReceiver {
	private Window subwindow;
	private KernelyDialogWindow confirmWindow;
	/**
	 * @see KernelyPresenter#bind()
	 */
	@SuppressWarnings("serial")
	public void bind() {
		
		SchedulingBundle.getEventBus().addListener(this);

		this.view.getAddButton().addListener(new ClickListener(){
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick (Button.ClickEvent event) {
				addEditJob(false);
			}
		});

		// The button is visible only when there is at least one job registered
		Map<Class <? extends Job>, JobDetail> map = SchedulingBundle.getSchedulingService().getRegisteredJobs();
		if (map.isEmpty()){
			this.view.getAddButton().setVisible(false);
		}

		this.view.getEditButton().addListener(new ClickListener(){
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick (Button.ClickEvent event) {
				addEditJob(true);
			}
		});
		
		this.view.getRefreshButton().addListener(new ClickListener(){
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick (Button.ClickEvent event) {
				fillJobsTable();
			}
		});
		
		this.view.getDisableButton().addListener(new ClickListener(){
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick (Button.ClickEvent event) {
				unscheduleJobProcess();
			}
		});
		

		
		
		fillJobsTable();
	}
	
	/**
	 * Called by a click on the lock button
	 */
	@SuppressWarnings("serial")
	private void unscheduleJobProcess(){
		final JobAndTriggerIdentifier selected = (JobAndTriggerIdentifier) this.view.getJobsTable().getValue();
		
		
		// Confirm window
		confirmWindow = new KernelyDialogWindow("Kernely - Unschedule job", "Do you really want to unschedule the job " + selected.getJob().getName() + " (scheduled with cron expression " + selected.getTrigger().getCronExpression()+ " ?", KernelyDialogWindow.ASKING_ICON);
		
		confirmWindow.setConfirmButtonCaption("Yes");
		confirmWindow.setCancelButtonCaption("No");
		// Adding listeners on window's "confirm" buttons click
		confirmWindow.getConfirmButton().addListener(new Button.ClickListener() {
			/**
			 * @see com.vaadin.ui.Button.ClickListener#buttonClick(com.vaadin.ui.Button.ClickEvent)
			 */
			public void buttonClick(ClickEvent event) {
				unscheduleJob(selected.trigger.getName(),selected.trigger.getGroup());
			}
		});
		
		view.getWindow().addWindow(confirmWindow);
	}
	
	private void unscheduleJob(String triggerName, String triggerGroup){
		try {
			KernelyQuartzScheduler.getScheduler().unscheduleJob(triggerName, triggerGroup);
			SchedulingBundle.getEventBus().broadcastEvent(new SchedulingRefreshEvent(this));
		} catch (SchedulerException e) {
			view.getWindow().showNotification(new KernelyNotification("The job can't be unschedule. Cause: "+e.getMessage(), KernelyNotification.ERROR_ICON));
		}
		// Remove the confirm window
		view.getWindow().removeWindow(confirmWindow);
	}

	private void fillJobsTable(){
		this.view.getJobsTable().removeAllItems();

		String[] jobGroups;
		String[] jobsInGroup;
		int i;
		int j;
		try {
			jobGroups = KernelyQuartzScheduler.getScheduler().getJobGroupNames();
			String groupName;
			String jobName;
			for (i = 0; i < jobGroups.length; i++) {
				groupName = jobGroups[i];
				jobsInGroup = KernelyQuartzScheduler.getScheduler().getJobNames(groupName);


				for (j = 0; j < jobsInGroup.length; j++) {
					jobName = jobsInGroup[j];

					// Get triggers on the job
					Trigger[] triggers = KernelyQuartzScheduler.getScheduler().getTriggersOfJob(jobName, groupName);

					// List all triggers
					for (Trigger trigger : triggers){
						if (trigger instanceof CronTrigger){
							CronTrigger cronTrigger = (CronTrigger) trigger;

							JobDetail detail = KernelyQuartzScheduler.getScheduler().getJobDetail(jobName, groupName);
							

							SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE MMMM F, H:m:s, (yyyy)");
							Date startTime = cronTrigger.getStartTime();
							String startString = "-";
							Date previousTime = cronTrigger.getPreviousFireTime();
							String previousString = "-";
							Date nextTime = cronTrigger.getNextFireTime();
							String nextString = "-";
							Date endTime = cronTrigger.getEndTime();
							String endString = "-";
							
							if (startTime != null){
								startString = dateFormat.format(startTime);
							}
							if (previousTime != null){
								previousString = dateFormat.format(previousTime);
							}
							if (nextTime != null){
								nextString = dateFormat.format(nextTime);
							}
							if (endTime != null){
								endString = dateFormat.format(endTime);
							}
							
							// Fill the table
							JobAndTriggerIdentifier identifier = new JobAndTriggerIdentifier(detail, cronTrigger);
							this.view.getJobsTable().addItem(new Object[] {
									jobName,
									detail.getDescription(),
									startString,
									previousString,
									nextString,
									endString,
									cronTrigger.getCronExpression()},
									identifier);
						}
					}
				}
			}
		} catch (SchedulerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * A class associating a job and a trigger
	 */
	public class JobAndTriggerIdentifier{
		private JobDetail job;
		private CronTrigger trigger;
		
		/**
		 * Default constructor.
		 * @param jobDetail The job.
		 * @param trigger The trigger.
		 */
		public JobAndTriggerIdentifier(JobDetail jobDetail, CronTrigger trigger){
			this.job = jobDetail;
			this.trigger = trigger;
		}

		/**
		 * Gets the job
		 * @return the job
		 */
		public JobDetail getJob() {
			return job;
		}

		/**
		 * Gets the trigger
		 * @return the trigger
		 */
		public CronTrigger getTrigger() {
			return trigger;
		}
		
	}

	private void addEditJob(boolean editionMode) {
		AddEditJobPresenter addJobPresenter = null;
		AddEditJobView addJobView;
		subwindow = new Window("Kernely - New job");
		if (editionMode){
			addJobPresenter = new AddEditJobPresenter((JobAndTriggerIdentifier) this.view.getJobsTable().getValue());
		} else {
			addJobPresenter = new AddEditJobPresenter();
		}

		subwindow.setModal(true);
		subwindow.setResizable(false);
		view.getWindow().addWindow(subwindow);
		subwindow.getContent().setSizeUndefined();
		addJobView = new AddEditJobView();
		addJobPresenter.setView(addJobView);
		subwindow.setContent((Layout)addJobPresenter.getView());

	}

	/**
	 * Called when an event is send throw KernelyBus
	 */
	public void handleKernelyEvent(KernelyEvent event) {
		if (event instanceof SchedulingRefreshEvent){
			this.fillJobsTable();
		}
	}



}
